home *** CD-ROM | disk | FTP | other *** search
/ Mac OS 9 Serial Number Archive / SN Archive 2023.11.04.toast / BSNG / SDK / BSNG SDK 2.5 / Libraries / standard utils / standard utils.c next >
Encoding:
C/C++ Source or Header  |  1998-02-05  |  23.0 KB  |  946 lines  |  [TEXT/CWIE]

  1. /*
  2.  * $Workfile:: standard utils.c                                               $
  3.  * $Revision:: 1                                                              $
  4.  *
  5.  * $Author:: Buck Rogers                                                      $
  6.  * $Modtime:: 30.09.1997 17:49 Uhr                                            $
  7.  *
  8.  * $History:: standard utils.c                                                $
  9.  * 
  10.  * *****************  Version 1  *****************
  11.  * User: Buck Rogers  Date: 30.09.1997   Time: 18:31 Uhr
  12.  * Created in $/BSNG/Plugins/BSNG SDK/Libraries/standard utils
  13.  * Adding subproject 'BSNG' to '$/'
  14.  *
  15.  * $NoKeywords::                                                              $
  16.  */
  17.  
  18.  
  19. #include "UltraU.h"
  20. #include "standard utils.h"
  21.  
  22.  
  23. /* ************************************************************************************************ */
  24. //RANDOM NUMBER GENERATION UTILITIES
  25.                      
  26. Boolean myBooleanRandom(void)
  27. {
  28.     return ((Boolean) Ultra_short1());
  29. }
  30.  
  31. unsigned short myShortRangedRandom(unsigned short min,unsigned short max)
  32. {
  33. register unsigned short        qdRdm;        //treat return value as 0-65536
  34. register unsigned long        range,t;
  35.  
  36.     qdRdm =(unsigned short) Ultra_short16();
  37.     range =max-min;
  38.     if (range != 1) t = (qdRdm * range) >> 16;        //now 0 <= t <= range
  39.     else            t = (qdRdm % 2);
  40.     return (t+min);
  41. }
  42.  
  43. unsigned long myLongRangedRandom(unsigned long min,unsigned long max)
  44. {
  45. register unsigned long    t,range=max-min;
  46.     
  47.     if (range < (1L << 16)) t=min + (unsigned long) ((unsigned short) myShortRangedRandom(0,range));
  48.     else
  49.     {
  50.         do {
  51.             t=(((unsigned long)myShortRangedRandom(0,range>>16))<<16) | myShortRangedRandom(0,range&0xFFFF);
  52.             t+=min;
  53.         } while ((t<min)||(t>max));
  54.     }
  55.     return (t);
  56. }
  57.  
  58. /* ************************************************************************************************ */
  59. //INTEGER/WHOLE NUMBER MATHEMATICAL/MANIPULATION ROUTINES
  60.  
  61. unsigned long myABSL(signed long n)
  62. {
  63.     return ((n >= 0) ? n : -n);
  64. }
  65.  
  66. unsigned short myABSW(signed short n)
  67. {
  68.     return ((n >= 0) ? n : -n);
  69. }
  70.  
  71. //warning in the bit rotation routines I have not bothered to do arguement reduction on b
  72. //so if you pass an out of range b, you will always get zero.  I may change this at some point, so
  73. //do not depend upon this 'functionality'
  74.  
  75. //the next two calls provide particularily wierd yet commonly used operation that is identical to
  76. //the rotate operation with the important differences being that the sign is used to borrow when
  77. //doing the right shifting components of the two operations and instead of oring we exclusive-or
  78.  
  79. unsigned char myArithROLB(unsigned char n,unsigned short b)
  80. {
  81.     register signed char    v=(signed char) n;
  82.     
  83.     return ((v << b) ^ (v >> (8 - b)));
  84. }
  85.  
  86. unsigned char myArithRORB(unsigned char n,unsigned short b)
  87. {
  88.     register signed char    v=(signed char) n;
  89.     
  90.     return ((v >> b) ^ (v << (8 - b)));
  91. }
  92.  
  93. unsigned char myROLB(unsigned char n,unsigned short b)
  94. {
  95.     register unsigned char    v=n;
  96.     
  97.     return ((v << b) | (v >> (8 - b)));
  98. }
  99.  
  100. unsigned char myRORB(unsigned char n,unsigned short b)
  101. {
  102.     register unsigned char    v=n;
  103.     
  104.     return ((v >> b) | (v << (8 - b)));
  105. }
  106.  
  107. unsigned short myROLW(unsigned short n,unsigned short b)
  108. {
  109.     register unsigned short    v=n;
  110.     
  111.     return ((v << b) | (v >> (16 - b)));
  112. }
  113.  
  114. unsigned short myRORW(unsigned short n,unsigned short b)
  115. {
  116.     register unsigned short    v=n;
  117.     
  118.     return ((v >> b) | (v << (16 - b)));
  119. }
  120.  
  121. unsigned long myROLL(unsigned long n,unsigned short b)
  122. {
  123.     register unsigned long    v=n;
  124.     
  125.     return ((v << b) | (v >> (32 - b)));
  126. }
  127.  
  128. unsigned long myROLLByteX(unsigned long n,unsigned short theByte,unsigned short b)
  129. {
  130.     register unsigned short    j=theByte * 8;
  131.     register unsigned long    u=n;
  132.     register unsigned char    v=(unsigned char) ((u >> j) & 0x000000FF);
  133.     
  134.     return ((u ^ (v << j)) | ((((v << b) | (v >> (8 - b))) & 0x000000FF) << j));
  135. }
  136.  
  137. unsigned long myROLLWordX(unsigned long n,unsigned short theWord,unsigned short b)
  138. {
  139.     register unsigned short    j=theWord * 16;
  140.     register unsigned long    u=n;
  141.     register unsigned short    v=(unsigned short) ((u >> j) & 0x0000FFFF);
  142.     
  143.     return ((u ^ (v << j)) | ((((v << b) | (v >> (16 - b))) & 0x0000FFFF) << j));
  144. }
  145.  
  146. unsigned long myRORL(unsigned long n,unsigned short b)
  147. {
  148.     register unsigned long    v=n;
  149.     
  150.     return ((v >> b) | (v << (32 - b)));
  151. }
  152.  
  153. unsigned long myRORLByteX(unsigned long n,unsigned short theByte,unsigned short b)
  154. {
  155.     register unsigned short    j=theByte * 8;
  156.     register unsigned long    u=n;
  157.     register unsigned char    v=(unsigned char) ((u >> j) & 0x000000FF);
  158.     
  159.     return ((u ^ (v << j)) | ((((v >> b) | (v << (8 - b))) & 0x000000FF) << j));
  160. }
  161.  
  162. unsigned long myRORLWordX(unsigned long n,unsigned short theWord,unsigned short b)
  163. {
  164.     register unsigned short    j=theWord * 16;
  165.     register unsigned long    u=n;
  166.     register unsigned short    v=(unsigned short) ((u >> j) & 0x0000FFFF);
  167.     
  168.     return ((u ^ (v << j)) | ((((v >> b) | (v << (16 - b))) & 0x0000FFFF) << j));
  169. }
  170.  
  171. unsigned long myIntegerSquareRoot(unsigned long n)    //extremely poor sqrRoot algorithm
  172. {
  173. register unsigned long v,sqr;
  174.  
  175.     v=n/2;
  176.     sqr=v*v;
  177.     while (sqr>n)
  178.     {
  179.         v=v/2;
  180.         sqr=v*v;
  181.     }
  182.     while (sqr<n)
  183.     {
  184.         v+=1;
  185.         sqr=v*v;
  186.     }
  187.     if (sqr>n) v--;
  188.     return v;
  189. }
  190.  
  191. unsigned long myClosestIntegerSquareRoot(unsigned long n)    //extremely poor algorithm
  192. {
  193. register unsigned long v,sqr;
  194.  
  195.     v=myIntegerSquareRoot(n);                                    //now    v*v <= n < (v+1)*(v+1)
  196.     sqr=v*v;
  197.     if ((n-sqr) > (sqr + (v<<1) +1 - n)) v++;                //v=v+1 iff (n-v*v) > ((v+1)*(v+1) - n)
  198.     return v;    
  199.     //note (sqr + (v<<1) +1) = v*v + 2*v + 1 = (v+1) * (v+1)
  200. }
  201.  
  202. /* ************************************************************************************************ */
  203. //NUMERIC STRING and NUMBER<-->STRING ROUTINES
  204.  
  205. unsigned short myBaseXCharToVal(unsigned char c)    //c should be '0'..'9','A'..'Z','a'..'z'
  206. {
  207.     if (c<='9') return (c-'0');
  208.     if (c<='Z') return (c-'A'+10);
  209.     if (c<='z') return (c-'a'+36);
  210.     return (0);
  211. }
  212.  
  213. /*
  214.     StringToNum() is well defined even for non-numeric strings and is equivalent to:
  215. */
  216. long myPStrToNum(const Str255 s)
  217. {
  218.     return myCharsToNum((StringPtr) &s[1],s[0]);
  219. }
  220.  
  221. long myCharsToNum(const StringPtr s,unsigned short numDigits)
  222. {
  223. register long    v;
  224. register short    i,len=numDigits;
  225. register short    sign=s[0];
  226.  
  227.     v=0;
  228.     if (len)
  229.     {
  230.         if ((sign=='+')||(sign=='-'))
  231.         {
  232.             for (i=1;i<len;i++) v=(v*10)+(s[i]&0x0F);    //note &0x0F==%16 but &0x0F is faster
  233.             if (sign=='-') v*=-1;
  234.         }
  235.         else for (i=0;i<len;i++) v=(v*10)+(s[i]&0x0F);    //note &0x0F==%16 but &0x0F is faster    
  236.     }
  237.     return v;
  238. }
  239.  
  240. long myDigitsToNum(const StringPtr s,unsigned short numDigits)
  241. {
  242.     return myBaseBDigitsToNum(s,10,numDigits);
  243. }
  244.  
  245. long myBaseBPStrToNum(const Str255 s,unsigned short b)
  246. {
  247.     return myBaseBDigitsToNum((StringPtr) &s[1],b,s[0]);
  248. }
  249.  
  250. long myBaseBDigitsToNum(const StringPtr s,unsigned short b,unsigned short numDigits)
  251. {
  252. register unsigned long    v = 0;                //defined so v can hold a positive 32 bit number
  253. register short            i,len=numDigits;
  254. register short            sign=s[0];
  255.  
  256.     if (len)
  257.     {
  258.         if ((sign == '+') || (sign == '-'))
  259.         {
  260.             for (i = 1; i < len; i++)  v = (v * b) + myBaseXCharToVal(s[i]);
  261.             if (sign == '-') return (- ((signed long) v));
  262.         }
  263.         else for (i = 0; i < len; i++) v = (v * b) + myBaseXCharToVal(s[i]);
  264.     }
  265.     return ((signed long) v);
  266. }
  267.  
  268. void myBaseBRandomPStr(Str255 s,unsigned short b,unsigned short numDigits)
  269. {
  270.     s[0]=numDigits;
  271.     myBaseBRandomDigits(&s[1],b,numDigits);
  272. }
  273.  
  274. void myBaseBRandomDigits(StringPtr s,unsigned short b,unsigned short numDigits)
  275. {
  276. register short    i;
  277. register short    max = b - 1;
  278.  
  279.     for (i=numDigits-1;i>=0;i--) s[i] = myValToBaseXChar(myShortRangedRandom(0,max));
  280. }
  281.  
  282. void mySFBaseBRandomPStr(Str255 s,unsigned short b,unsigned short numSigDigits)
  283. {
  284.     s[0]=numSigDigits;
  285.     mySFBaseBRandomDigits(&s[1],b,numSigDigits);
  286. }
  287.  
  288. void mySFBaseBRandomDigits(StringPtr s,unsigned short b,unsigned short numSigDigits)
  289. {
  290. register short    i;
  291. register short    max = b - 1;
  292.  
  293.     for (i=numSigDigits-1;i>=1;i--) s[i] = myValToBaseXChar(myShortRangedRandom(0,max));
  294.     s[0] = myValToBaseXChar(myShortRangedRandom(1,max));
  295. }
  296.  
  297. unsigned char myRandom09Char(void)
  298. {
  299.     return ((unsigned char) myShortRangedRandom('0','9'));
  300. }
  301.  
  302. unsigned char myRandomAZChar(void)
  303. {
  304.     return ((unsigned char) myShortRangedRandom('A','Z'));
  305. }
  306.  
  307. unsigned char myRandom09AZChar(void)
  308. {
  309. unsigned char    c;
  310.  
  311.     c = myShortRangedRandom(0,35);
  312.     c+= (c < 10) ? '0' : 'A'-10;
  313.     return (c);
  314. }
  315.  
  316. void myZeroPadPStr(Str255 s,unsigned short paddedLength)
  317. {
  318. register short    paddingLength=paddedLength-s[0];
  319.  
  320.     if (paddingLength>0)
  321.     {
  322.         BlockMove((Ptr) &s[1],(Ptr) &s[paddingLength+1],s[0]);
  323.         s[0]+=paddingLength;
  324.         while (paddingLength>0) s[paddingLength--]='0';
  325.     }
  326. }
  327.  
  328. unsigned char myValToBaseXChar(unsigned short v)
  329. {
  330.     if (v<10) return ('0'+v);        //00..09  -> '0'..'9'
  331.     if (v<36) return ('A'-10+v);    //10..35  -> 'A'..'Z'
  332.     return ('a'-36+v);                //36..61+ -> 'a'..'z'+
  333. }
  334.  
  335. void mySNumToPStr(long num,Str255 s,unsigned short minDigits)
  336. {
  337.     if (num >= 0)
  338.     {
  339.         NumToString(num,s);
  340.         myZeroPadPStr(s,minDigits);
  341.     }
  342.     else
  343.     {
  344.         NumToString(-num,s);
  345.         myZeroPadPStr(s,minDigits);
  346.         if (s[1]=='0') s[1]='-';
  347.         else myPrefixPStr(s,"\p-");
  348.     }
  349.  
  350. }
  351.  
  352. void myUNumToPStr(unsigned long n,Str255 s,unsigned short minDigits)
  353. {
  354.     s[0] = myUNumToDigits(n,&s[1],minDigits);
  355. }
  356.  
  357. void myUNumToBaseBPStr(unsigned long n,Str255 s,unsigned short b,unsigned short minDigits)
  358.     s[0] = myUNumToBaseBDigits(n,&s[1],b,minDigits);
  359. }
  360.  
  361. unsigned short myUNumToDigits(unsigned long n,StringPtr s,unsigned short minDigits)
  362. {
  363. register char    numStr[10];        //only 10 decimal digits are possible from unsigned 32 bits
  364. register short    start,i,j=0;
  365.  
  366.     do
  367.     {
  368.         numStr[j++]='0'+(n%10);
  369.         n/=10;
  370.     } while (n>0);
  371.     start=(j<minDigits) ? (minDigits-j) : 0;
  372.     for (i=0;i<start;i++) s[i]='0';
  373.     for (i=start;j>0;i++) s[i]=numStr[--j];
  374.     return (i);
  375. }
  376.  
  377. unsigned short myUNumToBaseBDigits(unsigned long n,StringPtr s,unsigned short b,unsigned short minDigits)
  378. {
  379. register char    numStr[32];        //32 binary digits are possible from unsigned 32 bits
  380. register short    start,i,j=0;
  381.  
  382.     if ((b<2) || (b>62)) return (0);    //error - illegal base was passed
  383.     do
  384.     {
  385.         numStr[j++]=myValToBaseXChar(n%b);
  386.         n/=b;
  387.     } while (n>0);
  388.     start=(j<minDigits) ? (minDigits-j) : 0;
  389.     for (i=0;i<start;i++) s[i]='0';
  390.     for (i=start;j>0;i++) s[i]=numStr[--j];
  391.     return (i);
  392. }
  393.  
  394. unsigned long mySumOfPStr(const Str255 s)                        //does not include the length byte
  395. {
  396. register unsigned long    result=0;
  397. register unsigned short    i;
  398.     
  399.     for (i = s[0]; i > 0; i--) result+=s[i];
  400.     return (result);
  401. }
  402.  
  403. unsigned long myIndexWeightedSumOfPStr(const Str255 s)            //does not include the length byte
  404. {
  405. register unsigned long    result=0;
  406. register unsigned short    i;
  407.     
  408.     for (i = s[0]; i > 0; i--) result+=i * s[i];
  409.     return (result);
  410. }
  411.  
  412. unsigned long mySumOfChars(const StringPtr s,unsigned short numChars)
  413. {
  414. register unsigned long    result=0;
  415. register unsigned short    i;
  416.     
  417.     for (i = 0; i < numChars; i++) result+=s[i];
  418.     return (result);
  419. }
  420.  
  421. unsigned long mySumOfBaseXPStr(const Str255 s)                    //does not include the length byte
  422. {
  423. register unsigned long    result=0;
  424. register unsigned short    i;
  425.     
  426.     for (i = s[0]; i > 0; i--) result+=myBaseXCharToVal(s[i]);
  427.     return (result);
  428. }
  429.  
  430. unsigned long mySumOfBaseXDigits(const StringPtr s,unsigned short numDigits)
  431. {
  432. register unsigned long    result=0;
  433. register unsigned short    i;
  434.     
  435.     for (i = 0; i < numDigits; i++) result+=myBaseXCharToVal(s[i]);
  436.     return (result);
  437. }
  438.  
  439. unsigned long my4BytesAsUNum(const StringPtr s)
  440. {
  441. register unsigned long    v;
  442. register StringPtr        c=s;
  443.  
  444.     v =*(c++)<<8;
  445.     v|=*(c++);
  446.     v<<=8;
  447.     v|=*(c++);
  448.     v<<=8;
  449.     v|=*c;
  450.     return (v);
  451. }
  452.  
  453. unsigned long my2BytesAsUNum(const StringPtr s)
  454. {
  455. register unsigned long    v;
  456. register StringPtr        c=s;
  457.     
  458.     v =*(c++)<<8;
  459.     v|=*c;
  460.     return (v);
  461. }
  462.  
  463. /* ************************************************************************************************ */
  464. //STRING MANIPULATION ROUTINES
  465.  
  466. unsigned long cStrLen(const Ptr s,unsigned long maxLen)
  467. {
  468. register Ptr c=s;
  469. register unsigned long len=0;
  470.     
  471.     while ((len < maxLen) && ((Byte *) *(c++)!=0x00)) len++;
  472.     return len;
  473. }
  474.  
  475. void myCStrToPStr(unsigned char *s)
  476. {
  477. unsigned char    *t = s;
  478. unsigned char    *p = s;
  479. unsigned long    len;
  480.  
  481.     while (*t != 0) t++;
  482.     len = t - s;
  483.     p = t;
  484.     while (p != s) *(p--) = *(--t);
  485.     if (len > 255)
  486.     {
  487.         DebugStr("\pmyCStrToPStr: string to long");
  488.         len = 255;
  489.     }
  490.     s[0] = len;
  491. }
  492.  
  493. void myCopyPStr(const Str255 s,Str255 t)
  494. {
  495.     BlockMove((Ptr) s,(Ptr) t,s[0]+1);
  496. }
  497.  
  498. Boolean myEqualPStr(const Str255 s,const Str255 t)
  499. {
  500. register short    i=s[0];
  501.  
  502.     if (s[0]==t[0])
  503.     {
  504.         while ((i>0) && (s[i]==t[i])) i--;
  505.         return ((Boolean)(i==0));
  506.     }
  507.     return (FALSE);
  508. }
  509.  
  510. short myFindFirstInPStr(const Str255 s,unsigned char c)
  511. {
  512.     register short    i    =1;
  513.     register short    len    =s[0];
  514.     
  515.     while ((i <= len) && (s[i] != c)) i++;
  516.     return ((i > len) ? 0 : i);
  517. }
  518.  
  519. short myFindLastInPStr(const Str255 s,unsigned char c)
  520. {
  521.     register short    i    =s[0];
  522.     
  523.     while ((i > 0) && (s[i] != c)) i--;
  524.     return (i);
  525. }
  526.  
  527. void myGetPStrSubString(const Str255 s,short first,unsigned short numChars,Str255 subStr)
  528. {
  529. register unsigned short    i,len=s[0];
  530. register unsigned short    j;
  531. register unsigned short    end;
  532.  
  533.     if (first == 0) DebugStr("\pBad parameter passsed to myGetPStrSubString");
  534.     if (first < 0)                                //first is an offset from the end of s
  535.     {
  536.         first+=len + 1;                            //map (-n..-1) to (1..len)
  537.         if (first <= 0) first = 1;                //requesting more chars than available - truncate
  538.     }
  539.     if ((len==0) || (first>len)) subStr[0]=0;    //s is null or first out of range -- return empty s
  540.     else
  541.     {
  542.         if (numChars == 0) numChars=len-first+1;//if (numChars == 0) subStr[1..n]=s[first..len]
  543.         end=first + numChars - 1;
  544.         if (end>len)                            //requesting more chars than available -- truncate
  545.         {
  546.             numChars-=end-len;
  547.             end=len;
  548.         }
  549.         for (i=end,j=numChars;i>=first;i--,j--) subStr[j]=s[i];
  550.         subStr[0]=numChars;
  551.     }
  552. }
  553.  
  554. void myPrefixPStr(Str255 s,const Str255 prefixStr)
  555. {
  556. register unsigned short    i=s[0];
  557. register unsigned short    j=prefixStr[0];
  558.     
  559.     if (j)
  560.     {
  561.         if ((i+j) <= 255)                                //if room to prefix
  562.         {
  563.             BlockMove((Ptr) &s[1],(Ptr) &s[j+1],i);
  564.             BlockMove((Ptr) &prefixStr[1],(Ptr) &s[1],j);    
  565.             s[0]+=j;
  566.         }
  567.         else DebugStr("\pOverflow");
  568.     }
  569. }
  570.  
  571. void myAppendPStr(Str255 s,const Str255 suffixStr)
  572. {
  573. register unsigned short    i=s[0];
  574. register unsigned short    j=suffixStr[0];
  575.     
  576.     if (j)
  577.     {
  578.         if ((i+j) <= 255)                                //if room to append
  579.         {
  580.             BlockMove((Ptr) &suffixStr[1],(Ptr) &s[i+1],j);
  581.             s[0]+=j;
  582.         }
  583.         else DebugStr("\pOverflow");
  584.     }
  585. }
  586.  
  587. void myAppendCharToPStr(Str255 s,unsigned char c)
  588. {
  589.     if (s[0] < 255) s[++s[0]] = c;
  590.     else DebugStr("\pOverflow");
  591. }
  592.  
  593. void myAppendQuotedPStr(Str255 s,const Str255 suffixStr)
  594. {
  595. register short        j=suffixStr[0];
  596.     
  597.     if ((j) && ((s[0]+2+j)<=255))    //if room to append
  598.     {
  599.         s[++s[0]] ='\'';
  600.         BlockMove((Ptr) &suffixStr[1],(Ptr) &s[++s[0]],j);    //note this pre-adds 1 to s[0]
  601.         s[s[0]+=j]='\'';                                    //index calculation also sets s[0]
  602.     }
  603. }
  604.  
  605. void myInsertInPStr(Str255 s,const Str255 insertStr,short offset)    //does an 'insert before'
  606. {
  607. register short    start,insertLen=insertStr[0];
  608. register short    len=s[0];
  609.  
  610.     if (insertLen > 0)
  611.     {
  612.         if (offset <= 0)                        //insert at 'offset' chars from end of s
  613.         {
  614.             start = len + offset + 1;
  615.             if (start < 1) start = 1;            //underflow - prefix        
  616.         }    
  617.         else                                    //insert at 'offset' chars from start of s
  618.         {
  619.             if (offset > len) offset = len + 1;    //overflow - suffix
  620.             start = offset;                
  621.         }
  622.         if (start <= len) BlockMove((Ptr) &s[start],(Ptr) &s[start+insertLen],len-start+1);    //make room for insertStr
  623.         BlockMove((Ptr) &insertStr[1],(Ptr) &s[start],insertLen);                             //copy inserStr into s
  624.         s[0]+=insertLen;
  625.     }
  626. }
  627.  
  628. void myBracketPStrWithChar(Str255 s,unsigned char c,signed short numBefore,signed short numAfter)
  629. {
  630. register short    i,j,len=s[0];
  631.     
  632.     if (numBefore < 0) numBefore = 0;
  633.     if (numAfter  < 0) numAfter = 0;    
  634.     if ((len + numBefore + numAfter) < 256)
  635.     {
  636.         if (numBefore)
  637.         {
  638.             i=len;                                                //i=initial length
  639.             len+=numBefore;                                        //set len=prefixed length
  640.             for (j=len; (i>0); i--) s[j--]=s[i];                //slide existing string forward
  641.             while (j>0) s[j--]=c;                                //write prefix
  642.         }
  643.         for (i=len,j=numAfter; j > 0 ; j--) s[++i]=c;            //write suffix
  644.         s[0]=i;                                                    //adjust length;
  645.     }
  646. }
  647.  
  648. void myUnBracketPStrWithChar(Str255 s,unsigned char c,Boolean doBefore,Boolean doAfter)
  649. {
  650. register unsigned short    len    = s[0];
  651. register unsigned char    *t    =&s[1];
  652.     
  653.     if (doAfter)
  654.     {
  655.         while ((len > 0) && (s[len] == c)) len--;
  656.         s[0]=len;
  657.     }
  658.     if (doBefore)
  659.     {
  660.         while ((len > 0) && (*(t++) == c)) len--;    
  661.         //note: len != s[0] implies that *(--t) is the first non-c character in s    
  662.         if (len != s[0])    
  663.         {
  664.             BlockMove((Ptr) --t,(Ptr) &s[1],len);
  665.             s[0]=len;
  666.         }
  667.     }
  668. }
  669.  
  670. void myStripCharFromPStr(Str255 s,unsigned char c)
  671. {
  672. register unsigned short        i,j,len = s[0];
  673.  
  674.     for (i = 1, j = 0; i <= len; i++) if (s[i] != c) s[++j] = s[i];
  675.     s[0] = j;
  676. }
  677.  
  678. void myDeleteElementFromPStr(Str255 s,unsigned short index)
  679. {
  680. register unsigned short        i,len = s[0];
  681.  
  682.     if (index <= len)
  683.     {
  684.         for (i = index; i < len; i++) s[i] = s[i + 1];
  685.         s[0]--;
  686.     }
  687. }
  688.  
  689.  
  690. void myUpCasePStr(Str255 s)
  691. {
  692. short            i;
  693.  
  694.     for (i=s[0];i>0;i--) if ((s[i]>='a') && (s[i]<='z')) s[i]-='a'-'A';
  695. }
  696.  
  697. void myLoCasePStr(Str255 s)
  698. {
  699. register short    i;
  700.  
  701.     for (i=s[0];i>0;i--) if ((s[i]>='A') && (s[i]<='Z')) s[i]+='a'-'A';
  702. }
  703.  
  704. void myTitleCasePStr(Str255 s)
  705. {
  706. register short    i=1;
  707. register short    len=s[0];
  708.  
  709.     if (len)
  710.     {
  711.         myLoCasePStr(s);
  712.         while (i<=len)
  713.         {
  714.             if ((s[i]>='a') && (s[i]<='z')) s[i]-='a'-'A';    //capitalize the ith character
  715.             while ((i<=len)  && (s[i]!=' ')) i++;            //skip until space
  716.             while ((i<=len)  && (s[i]==' ')) i++;            //skip spaces
  717.         }
  718.     }
  719. }
  720.  
  721. void myTruncatePStr(Str255 s,unsigned short maxLength)
  722. {
  723.     if (s[0] > (unsigned short) maxLength) s[0]=(unsigned char) maxLength;
  724. }
  725.  
  726. void myReversePStr(Str255 s)
  727. {
  728. register short            i,j;
  729. register unsigned char    t;
  730.  
  731.     for (i=s[0],j=1 ;i>j; i--,j++)    //note this algorithm will not waste time exchanging
  732.     {                                //a len=1 string or middle element with itself
  733.         t=s[i];
  734.         s[i]=s[j];
  735.         s[j]=t;
  736.     } 
  737. }
  738.  
  739. void myMapPStr(Str255 s,unsigned short *permIndexes)
  740. {
  741. register unsigned short    i,len = s[0];
  742. register Str255            t;
  743.  
  744.     //do the permutation
  745.     for (i = 0; i <= len; i++) t[i] = s[permIndexes[i]];
  746.     //t may or may not be a PStr now, so do a direct copy
  747.     BlockMove( (Ptr) t, (Ptr) s, len + 1);
  748. }
  749.  
  750. void myInversePermutatePStr(Str255 s,unsigned short *permIndexes)
  751. {
  752. register unsigned short    i,len = s[0];
  753. register Str255            t;
  754.  
  755.     //do the permutation
  756.     for (i = 0; i <= len; i++) t[permIndexes[i]] = s[i];
  757.     //t may or may not be a PStr now, so do a direct copy
  758.     BlockMove( (Ptr) t, (Ptr) s, len + 1);
  759. }
  760.  
  761. /* ************************************************************************************************ */
  762. //RESOURCE ROUTINES
  763.  
  764. Boolean mySaveResource(const Handle theResource)
  765. {
  766.     short    resAttributes;
  767.     Boolean itWorked;
  768.     
  769.     resAttributes=GetResAttrs(theResource);
  770.     if (resAttributes&resProtected)
  771.     {
  772.         SetResAttrs(theResource,resAttributes ^ resProtected);    //set as unprotected
  773.         ChangedResource(theResource);
  774.         itWorked=(Boolean) (ResError()==noErr); 
  775.         if (itWorked) WriteResource(theResource);
  776.         SetResAttrs(theResource,resAttributes);    //set as protected
  777.         //this setting will be saved even though we don't call changed/write resource
  778.     }
  779.     else 
  780.     {
  781.         ChangedResource(theResource);
  782.         itWorked=(Boolean) (ResError()==noErr); 
  783.         if (itWorked) WriteResource(theResource);
  784.     }
  785.     if (!itWorked) DebugStr("\pError returned by ChangedResource - cannot save");
  786.     return itWorked;
  787. }
  788.  
  789. /* ************************************************************************************************ */
  790. //STANDARD FILE ROUTINES
  791.  
  792. Boolean myPutFile(FSSpec *theFSSPtr,OSType type,OSType creator,const Str255 prompt,const Str255 defaultName)
  793. {
  794.     StandardFileReply     outputReply;
  795.     OSErr                errorCode=noErr;
  796.     
  797. putFile:
  798.     StandardPutFile(prompt,defaultName,&outputReply);
  799.     if (outputReply.sfGood)
  800.     {
  801.         if (outputReply.sfReplacing)
  802.         {
  803.             errorCode=FSpDelete(&(outputReply.sfFile));
  804.             if (errorCode!=noErr)
  805.             {
  806.                 SysBeep(10);    
  807.                 goto putFile;
  808.             }    
  809.         }
  810.         errorCode=FSpCreate(&(outputReply.sfFile),creator,type,outputReply.sfScript);
  811.         *theFSSPtr=outputReply.sfFile;                                    //copy the FSS
  812.     }
  813.     return ((outputReply.sfGood)&&(errorCode==noErr));
  814. }
  815.  
  816. Boolean myGetFile(FSSpec *theFSSPtr)
  817. {
  818.     SFTypeList            typeList;
  819.     StandardFileReply     reply;
  820.     
  821.     StandardGetFile(nil,-1,typeList,&reply);
  822.     *theFSSPtr=reply.sfFile;                                            //copy the FSS 
  823.     return ((reply.sfGood)&&(!reply.sfIsFolder)&&(!reply.sfIsVolume));    //file was selected?
  824. }
  825.  
  826. /* ************************************************************************************************ */
  827. //FILE ROUTINES 
  828.  
  829. OSErr myCloseFile(short *fileRefNum,FSSpec *fileFSSpec)
  830. {
  831.     OSErr    errorCode;
  832.     
  833.     errorCode=FSClose(*fileRefNum);
  834.     *fileRefNum=0;                            //safety to prevent double closing which can trash HD's
  835.     if (errorCode!=noErr) DebugStr("\pError closing file");
  836.     errorCode=FlushVol(nil,fileFSSpec->vRefNum);                      //ensure file data is written
  837.     if (errorCode!=noErr) DebugStr("\pError flushing volume");
  838.     return (errorCode);
  839. }
  840.  
  841. OSErr myOpenResFile(FSSpec *inputFSSPtr,short permission,short *inputRefNumPtr)
  842. {
  843.     short    oldResFile;
  844.     OSErr    errorCode=noErr;
  845.     
  846.     oldResFile=CurResFile();
  847.     SetResLoad(FALSE);                            //stop resources in users file from auto preloading
  848.     *inputRefNumPtr=FSpOpenResFile(inputFSSPtr,permission);
  849.     if (*inputRefNumPtr==-1) errorCode=ResError();
  850.     SetResLoad(TRUE);                            //resume normal loading of resources
  851.     UseResFile(oldResFile);
  852.     return errorCode;
  853. }
  854.  
  855. /* ************************************************************************************************ */
  856. //TEXT FILE OUTPUT ROUTINES
  857.  
  858. void myOutputPStr(short outputRefNum,const Str255 s)
  859. {
  860.     long    inOutCount=(long) s[0];
  861.     OSErr    errorCode;
  862.     
  863.     if (inOutCount!=0)
  864.     {
  865.         errorCode = FSWrite(outputRefNum,&inOutCount,&s[1]);
  866.         if (errorCode!=noErr) DebugStr("\pError during write");
  867.     }
  868. }
  869.  
  870. void myOutputSuffixedPStr(short outputRefNum,const Str255 s,const Str255 suffixStr)
  871. {
  872.     long    inOutCount=(long) s[0];
  873.     OSErr    errorCode;
  874.     
  875.     if (inOutCount!=0)
  876.     {
  877.         errorCode = FSWrite(outputRefNum,&inOutCount,&s[1]);
  878.         if (errorCode!=noErr) DebugStr("\pError during write");
  879.         else
  880.         {
  881.             inOutCount=(long) suffixStr[0];
  882.             if (inOutCount!=0)
  883.             {
  884.                 errorCode = FSWrite(outputRefNum,&inOutCount,&suffixStr[1]);
  885.                 if (errorCode!=noErr) DebugStr("\pError during write");
  886.             }
  887.         }
  888.     }
  889. }
  890.  
  891. void myOutputText(short outputRefNum,const Ptr TextPtr,unsigned long textLen)
  892. {
  893.     long    inOutCount=(long) textLen;
  894.     OSErr    errorCode;
  895.     
  896.     if (inOutCount!=0)
  897.     {
  898.         errorCode = FSWrite(outputRefNum,&inOutCount,TextPtr);
  899.         if (errorCode!=noErr) DebugStr("\pError during write");
  900.     }
  901. }
  902.  
  903. void myOutputSuffixedText(short outputRefNum,const Ptr TextPtr,unsigned long textLen,const Str255 suffixStr)
  904. {
  905.     long    inOutCount=(long) textLen;
  906.     OSErr    errorCode;
  907.     
  908.     if (textLen!=0)
  909.     {
  910.         errorCode = FSWrite(outputRefNum,&inOutCount,TextPtr);
  911.         if (errorCode!=noErr) DebugStr("\pError during write");
  912.         else
  913.         {
  914.             inOutCount=(long) suffixStr[0];
  915.             if (inOutCount!=0)
  916.             {
  917.                 errorCode = FSWrite(outputRefNum,&inOutCount,&suffixStr[1]);
  918.                 if (errorCode!=noErr) DebugStr("\pError during write");
  919.             }
  920.         }
  921.     }
  922. }
  923.  
  924. void myOutputResHeader(short outputRefNum,OSType theType,short theID,const Str255 theName)
  925. {
  926.     Str255        idStr,headerStr={"\p'????' #"};
  927.     const short    offsetToOSType=2;    //offset into headerStr at which to copy the OSType
  928.     long        inOutCount;
  929.     OSErr        errorCode;
  930.     
  931.     BlockMove((Ptr) &theType,(Ptr) (headerStr+offsetToOSType),4);    //copy OSType into headerStr
  932.     NumToString((long) theID,idStr);
  933.     myAppendPStr(headerStr,idStr);
  934.     if (theName[0]!=0)
  935.     {
  936.         myAppendPStr(headerStr,"\p '");
  937.         myAppendPStr(headerStr,theName);
  938.         myAppendPStr(headerStr,"\p'");
  939.     }
  940.     myAppendPStr(headerStr,"\p\r\r");
  941.     inOutCount=headerStr[0];
  942.     errorCode = FSWrite(outputRefNum,&inOutCount,(Ptr) &headerStr[1]);
  943.     if (errorCode!=noErr) DebugStr("\pError during write");
  944. }
  945.